package com.ltsh.plugin.mybatis;

import com.alibaba.druid.sql.SQLUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MybatisLogAnalysis {
    private static final List<String> basicTypes = Arrays.asList(new String[] { "Integer", "Long", "Double", "Float", "Boolean" });

    public static ResultObj analysisSql(Object content) {
        if (content == null || "".equals(content)) {
            return new ResultObj(false, "需要解析内容不能为空！");
        }
        String src = content.toString();
        String sqlPre = null;
        String paramPre = null;
        for (String tmp : GlobalConstant.PREFIX_SQL.split(",")) {
            if (src.contains(tmp)) {
                sqlPre = tmp;
                break;
            }
        }
        if (sqlPre == null) {
            return new ResultObj(false, "选定SQL内容不包含：" + GlobalConstant.PREFIX_SQL.replaceAll(",", " 或 "));
        }
        for (String tmp : GlobalConstant.PARAM_SQL.split(",")) {
            if (src.contains(tmp)) {
                paramPre = tmp;
                break;
            }
        }
        if (paramPre == null) {
            return new ResultObj(false, "选定参数内容不包含：" + GlobalConstant.PARAM_SQL.replaceAll(",", " 或 "));
        }
        // sql 内容开始下标
        int sqlStartIndex = src.indexOf(sqlPre) + sqlPre.length();
        // sql 内容结束下标
        int sqlEndIndex = src.indexOf(GlobalConstant.END_SPLIT, sqlStartIndex);
        // sql 内容开始下标
        int paramStartIndex = src.indexOf(paramPre) + paramPre.length();
        // sql 内容结束下标
        int paramEndIndex = src.indexOf(GlobalConstant.END_SPLIT, paramStartIndex);
        if (paramEndIndex == -1) {
            paramEndIndex = src.length();
        }
        List<String> params = getParams(src.substring(paramStartIndex, paramEndIndex));
        String sql = src.substring(sqlStartIndex, sqlEndIndex);
        if (params.isEmpty()) {
            return new ResultObj(true, formatSql(sql));
        }
        StringBuilder stringBuilder = new StringBuilder();
        String[] split = sql.split("\\?");
        for (int i = 0; i < split.length; i++) {
            stringBuilder.append(split[i]);
            if (i < params.size()) {
                stringBuilder.append(params.get(i));
            }
        }
        return new ResultObj(true, formatSql(stringBuilder.toString()));
    }

    public static String formatSql(String sql) {
        return SQLUtils.formatMySql(sql);
    }

    protected static List<String> getParams(String src) {
        if (src == null || src.length() == 0) {
            return null;
        }
        List<String> params = new ArrayList<>();
        String strNullValue = "null";
        String splitStr = ", ";
        int cursor = src.length();
        while (cursor > -1) {
            // 如果最后为null
            if (src.lastIndexOf(strNullValue, cursor) == cursor - strNullValue.length()) {
                // 设置值为null
                params.add(0, strNullValue);
                // 跳过", "
                cursor = src.lastIndexOf(strNullValue, cursor) - 2;
                continue;
            }
            // 参数日志格式为 参数1(Integer), 参数2(String)
            if (src.charAt(cursor - 1) == ')') {
                int typeStart = src.lastIndexOf('(', cursor);
                // 取到（）中间的参数类型
                String type = src.substring(typeStart + 1, cursor - 1);
                cursor = typeStart;
                int valueStart = src.lastIndexOf(splitStr, cursor);
                while (valueStart > -1 && src.lastIndexOf(strNullValue, valueStart) != valueStart - strNullValue.length()
                        && src.charAt(valueStart - 1) != ')') {
                    valueStart = src.lastIndexOf(splitStr, valueStart - 1);
                }
                String value = src.substring((valueStart == -1) ? 0 : (valueStart + 2), cursor);
                cursor = valueStart;
                // 判断是基础类型
                if (basicTypes.contains(type)) {
                    params.add(0, value);
                    continue;
                }
                // 其他类型以字符串显示
                params.add(0, "'" + value + "'");
                continue;
            }
            cursor = -1;
        }
        return params;
    }
}
